package com.example.yilanchatserver.application.config;

import com.example.yilanchatserver.common.I18nConfig;
import com.example.yilanchatserver.common.BasePageableEntity;
import com.example.yilanchatserver.common.ErrorCodeConstant;
import com.example.yilanchatserver.business.freechat.BaseResponseEntity;
import com.example.yilanchatserver.business.freechat.BusinessException;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

@RestControllerAdvice
public class GlobalExceptionHandler implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        Class<?> returnTypeClazz = returnType.getMethod().getReturnType();
        return returnTypeClazz != BaseResponseEntity.class && returnTypeClazz != BasePageableEntity.class;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        if (request.getURI().getRawPath().contains("swagger") || request.getURI().getRawPath().contains("api-docs")
                || request.getURI().getRawPath().contains("/diagram")) {
            return body;
        } else {
            if (body instanceof BaseResponseEntity || body instanceof BasePageableEntity) {
                return body;
            }
            return BaseResponseEntity.SUCCESS(body);
        }
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity exceptionHandler(Exception e) {
        e.printStackTrace();
        BaseResponseEntity baseResultVO = new BaseResponseEntity();
        baseResultVO.setCode(ErrorCodeConstant.INTERNAL_SERVER_ERROR);
        baseResultVO.setType("error");
        baseResultVO.setMessage(e.toString());
        return ResponseEntity.status(HttpStatus.OK).body(baseResultVO);
    }

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity businessException(HttpServletRequest request, BusinessException e) {
        BaseResponseEntity baseResultVO = new BaseResponseEntity();
        baseResultVO.setCode(ErrorCodeConstant.BUSINESS_EXCEPTION);
        baseResultVO.setType("error");
        baseResultVO.setMessage(I18nConfig.getMessage(request, e.getErrorCode()));
        return ResponseEntity.status(HttpStatus.OK).body(baseResultVO);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity methodArgumentNotValidExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
        BaseResponseEntity baseResultVO = new BaseResponseEntity();
        baseResultVO.setMessage(I18nConfig.getMessage(request, "ParamError") + e.getBindingResult().getFieldError().getDefaultMessage());
        baseResultVO.setCode(ErrorCodeConstant.BAD_REQUEST);
        baseResultVO.setType("error");
        return ResponseEntity.status(HttpStatus.OK).body(baseResultVO);
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity constraintViolationException(HttpServletRequest request, MissingServletRequestParameterException e) {
        BaseResponseEntity baseResultVO = new BaseResponseEntity();
        baseResultVO.setMessage(I18nConfig.getMessage(request, "ParamError") + e.getParameterName());
        baseResultVO.setCode(ErrorCodeConstant.BAD_REQUEST);
        baseResultVO.setType("error");
        return ResponseEntity.status(HttpStatus.OK).body(baseResultVO);
    }

}
